package com.pickgliss.utils
{
	import com.greensock.TweenLite;
	import com.pickgliss.loader.ModuleLoader;
	
	import flash.events.Event;
	import flash.events.NetStatusEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	
	public class SoundManager
	{
		private static const MusicFailedTryTime:int = 3;
		
		private var _soundDic:Dictionary;
		private var _currentSound:Dictionary;
		private var _allowSound:Boolean;
		
		private var _musicList:Array;//音乐列表
		private var _musicDic : Dictionary;
		private var _currentMusic:String;//当前音乐
		private var _currentMusicIndex:int;
		private var _allowMusic:Boolean;
		private var _musicLoop:Boolean;
		private var _musicPlaying:Boolean;//是否正在播放音乐
		
		private var _currentMusicTry:int = 0;
		
		private var _musicVolumn:Number;
		private var _soundVolumn:Number;
		
		private var _nc:NetConnection;
		private var _ns:NetStream;
		private var _ncII:NetConnection;
		private var _nsII : NetStream;
		private var _preNs : NetStream;
		private var _curNs: NetStream;
		
		private var _musicSite:String;
		
		private var _battleMapDic : Dictionary
		
		private static const WORLDBOSSMUSIC:String="BattleMusicBoss" ;
		private static const BOSSMUSIC:String="BattleMusicWorldBoss" ;
		private static const BATTLEMUSIC:String = "BattleMusic" ;
		private static const MAP_NUM:int= 11 ;
		
		public function get allowSound():Boolean
		{
			return _allowSound;
		}
		public function set allowSound(value:Boolean):void
		{
			if(_allowSound == value) return;
			_allowSound = value;
			if(_allowSound == false)
			{
				stopAllSound();
			}
		}
		
		public function get allowMusic():Boolean
		{
			return _allowMusic;
		}
		public function set allowMusic(value:Boolean):void
		{
			if(_allowMusic == value) return;
			_allowMusic = value;
			if(_allowMusic)
				resumeMusic();
			else
				pauseMusic();
		}
		
		public function get soundVolumn():Number
		{
			return _soundVolumn;
		}
		public function get musicVolumn():Number
		{
			return _musicVolumn;
		}
		
		public function SoundManager()
		{
			_soundDic = new Dictionary();
			_currentSound = new Dictionary();
//			_allowSound = true;
//			_allowMusic = true;
//			_musicVolumn = 100;
			_musicLoop = false;
			_musicPlaying = false;
			
			_nc = new NetConnection();
			_nc.connect(null);
			_ns = new NetStream(_nc);
			_ns.bufferTime = 0.3;
			_ns.client = this;
			_ns.addEventListener(NetStatusEvent.NET_STATUS,__netStatus);
			
			_ncII = new NetConnection();
			_ncII.connect(null);
			_nsII = new NetStream(_nc);
			_nsII.bufferTime = 0.3;
			_nsII.client = this;
			_nsII.addEventListener(NetStatusEvent.NET_STATUS,__netStatus);
			
			_musicDic = new Dictionary(true);
			_battleMapDic = new Dictionary(true);
		}
		
		
		
		/**
		 * 
		 * @param config 其中cls为类的完全限定名，path为*.flv的绝对路径,配置文件中只能有一个sounds和musics节点
		 * config格式：
		 * 		<sounds source="audio.swf">
		 * 			<sound id="001" cls="Sound001" />
		 * 			<sound id="002" cls="Sound002" />
		 * 			<sound id="003" cls="Sound003" />
		 * 		</sounds>
		 * 		<musics root="http://192.168.0.4/DandantangPVE/Resource/sound/">
		 * 			<music filename="001" />
		 * 			<music filename="002" />
		 * 			<music filename="003" />
		 * 		</musics>
		 * 		
		 *		
		 */		
		public function setup(config:XML):void
		{
			var source:String;
			
			var soundsXL:XMLList = config..sounds;
			for each(var xml:XML in soundsXL)
			{
				var soundXL:XMLList = xml..sound;
				source = xml.@source;
				
				for each(var x:XML in soundXL)
				{
					_soundDic[String(x.@id)] = String(x.@cls);
				}
			}
			
			var musicMainSite:String;
			
			
			var musicsXL:XMLList = config..musics;
			for each(var xm:XML in musicsXL)
			{
				var musicXL:XMLList = xm..music;
				musicMainSite = xm.@root;
				for each(var mx:XML in musicXL)
				{
					var musicStrAry:Array = String(mx.@filename).split(",");
					_musicDic[String(mx.@key)] = musicStrAry;
				}
			}
			
//			var battleMapXMLList : XMLList = config..battle_map
//			var mapMscs : Array;
//			for each(var map : XML in battleMapXMLList){
//				mapMscs = String(map.@filename).split(",");
//				_battleMapDic[int(map.@mapid)] = mapMscs
//				_musicDic["battle"] = _musicDic["battle"].concat(mapMscs)
//			}
			
			_musicSite = musicMainSite;		
			
			
			var sound:Sound = new Sound(new URLRequest(""));//防止最小化的时候降帧
			sound.play();
			sound.close();
		}
		
		public function initbattleMusics(arr : Array,  battleMapMusicDic:Dictionary):void
		{
			_musicDic["battle"] = arr;
			_battleMapDic=battleMapMusicDic;
		}
		
		public function setupAudioResource():void
		{
			
		}
		
		public function setConfig($allowSound:Boolean,$allowMusic:Boolean,$musicVolumn:Number,$soundVolumn:Number):void
		{
			allowMusic = $allowMusic;
			allowSound = $allowSound;
			_musicVolumn = $musicVolumn;
			_soundVolumn = $soundVolumn;
			_ns.soundTransform = new SoundTransform(_musicVolumn / 100);
			_nsII.soundTransform = new SoundTransform(_musicVolumn / 100);
		}
		
		//=====================================播放音效=====================================
		
		public function hasSound(id:String):Boolean
		{
			if(_soundDic[id] != null)
			{
				if((_soundDic[id] is String) && ModuleLoader.hasDefinition(_soundDic[id]))
				{
					_soundDic[id] = ModuleLoader.getDefinition(_soundDic[id]);
				}
				return true;
				
			}
			return false;
		}
		
		public function isPlaying(id:String):Boolean
		{
			return (_currentSound[id] != null);
		}
		
		public function play(id:String, allowMulti:Boolean = false, replaceSame:Boolean = true, loop:int = 0):void
		{
			if(hasSound(id) == false) return;
			
			if(_allowSound)
			{
				try
				{
					if(allowMulti || isPlaying(id) == false)
					{
						playSoundImp(id, replaceSame, loop);
					}
				}
				catch(e:Error)
				{
				}
			}
		}
		
		private function playSoundImp(id:String, replaceSame:Boolean, loop:Number):void
		{
			if(_currentSound[id] != null && replaceSame)
			{
				var _sc:SoundChannel = _currentSound[id] as SoundChannel;
				_sc.removeEventListener(Event.SOUND_COMPLETE, __soundComplete);
				_sc.stop();
				
				_currentSound[id] = null;
			}
			
			var ss:Sound = new _soundDic[id]();
			var sc:SoundChannel = ss.play(0,loop,new SoundTransform(_soundVolumn / 100));
			
			sc.addEventListener(Event.SOUND_COMPLETE,__soundComplete);
			_currentSound[id] = sc;
		}
		
		private function __soundComplete(e:Event):void
		{
			var sc:SoundChannel = e.currentTarget as SoundChannel;
			sc.removeEventListener(Event.SOUND_COMPLETE, __soundComplete);
			sc.stop();
			
			for(var str:String in _currentSound)
			{
				if(_currentSound[str] == sc)
				{
					_currentSound[str] = null;
					return;
				}
			}
		}
		
		public function stop(id:String):void
		{
			if(_currentSound[id])
			{
				_currentSound[id].removeEventListener(Event.SOUND_COMPLETE, __soundComplete);
				_currentSound[id].stop();
				_currentSound[id] = null;
			}
		}
		
		public function stopAllSound():void
		{
			for each(var sc:SoundChannel in _currentSound)
			{
				if(sc){
				sc.removeEventListener(Event.SOUND_COMPLETE, __soundComplete);
				sc.stop();
				}
			}
			_currentSound = new Dictionary();
		}
		
		//=====================================播放音效=====================================
		
		//===================================播放背景音乐====================================
		/**
		 *state 场景
		 * id == -1随机播放当前场景的音乐 
		 */		
		private var _currentState : String;
		public static const CASTLE  : String = "castle";
		public static const OUTER_CITY : String = "outercity";
		public static const BATTLE : String = "battle";
		public static const FARM   : String = "farm";
		public static const CAMPAIGN_SUCCEED : String = "campaign_succeed";
		public static const VEHICLE   : String = "vehicle";
		public function playMusic(state:String,index:int=-1, loops:Boolean = true, replaceSame:Boolean = false):void
		{
			_musicList = _musicDic[state] as Array;
			_currentMusicTry = 0;
			if(index == -1 || index >= _musicList.length)index = getRandomIndex();
			if(_currentMusic != _musicList[index] || replaceSame)
			{
				prepared();
//				if(_musicPlaying)
//					stopMusic();
				playMusicImp(index,loops);
			}
		}
		public function getMusicListByType(type : String):Array
		{
			return _musicDic[type] as Array;
		}
		public function getBattleMapMusics(mapId : int):Array
		{
			return _battleMapDic[mapId]
		}
		/**
		 * 动态播放音乐，不同副本播放不同的音乐 
		 * 
		 */		
		public function dynamicPlayMusic(musics : String,loops:Boolean=true,replaceSame:Boolean = false):void
		{
			if(!musics)return;
			_musicList = musics.split(",");
			_currentMusicTry = 0;
			var index : int = getRandomIndex();
			if(_currentMusic != _musicList[index] || replaceSame)
			{
				prepared();
				playMusicImp(index,loops);
			}
		}
		private function prepared() : void
		{
			_preNs = (_curNs != _ns ? _nsII : _ns);
			_preNs.removeEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
			_curNs = (_curNs == _ns ? _nsII : _ns);
			
			_musicPlaying = false;
			_currentMusic = null;
			_currentMusicIndex = -1;
		}
		private function getRandomIndex() : int
		{
			var index : int = Math.random()*_musicList.length;
			return index;
		}
		
		private function getMusicIndexByID(id:String):int
		{
			var rlt:int = _musicList.indexOf(id);
			
			return (rlt == -1 ? 0 : rlt);
		}
		
		private var _musicCanStart : Boolean;
		private var _fadeOutTweener : TweenLite
		private var _fadeInTweener : TweenLite;
		private function playMusicImp(index:int, loops:Boolean):void
		{
			if(index >= _musicList.length) index = 0;
			
			_musicLoop = loops;
			if(_musicList.length > 0)
			{
				_currentMusicIndex = index;
				_currentMusic = _musicList[index];
				_musicPlaying = true;
				_curNs.play(_musicSite + _currentMusic + ".flv");
				_curNs.soundTransform = new SoundTransform(0);//new SoundTransform(_musicVolumn / 100);
				
				if(_allowMusic)
				{
					_musicCanStart = false;
					_curNs.addEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
					removeMusicTweener();
					var sndChannel : SoundTransform = new SoundTransform(_musicVolumn / 100);
					_fadeOutTweener = TweenLite.to(sndChannel, 1.5, {volume:0.4, onUpdate:updateFadeOutChannel, 
						onUpdateParams:[_preNs, sndChannel], onComplete : musicFadeOutComplete,
						onCompleteParams:[_preNs]});
				}
				else
				{
					_curNs.removeEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
					pauseMusic();
				}
			}
		}
		private function updateFadeOutChannel(soundStr : NetStream, sndChannel : SoundTransform):void
		{
			soundStr.soundTransform = new SoundTransform(sndChannel.volume);
		}
		
		private function musicFadeOutComplete(soundStr : NetStream):void
		{
			_fadeOutTweener = null;
			try{
				soundStr.close();
			}
			catch(err :Error){};
			if(_musicCanStart){
				var sndChannel : SoundTransform = new SoundTransform(0);
				_curNs.soundTransform = sndChannel
				_fadeInTweener = TweenLite.to(sndChannel, 1.5, {volume:_musicVolumn / 100, 
					onUpdate:onMusicFadeInUpdate, onUpdateParams:[sndChannel],
					onComplete : musicFadeInComplete});
				resumeMusic();
			}
		}
		private function onMusicFadeInUpdate(sndChannel : SoundTransform):void
		{
			_curNs.soundTransform = new SoundTransform(sndChannel.volume);
		}
		private function musicFadeInComplete():void
		{
			_fadeInTweener = null;
		}
		private function removeMusicTweener():void
		{
			if(_fadeOutTweener){
				_fadeOutTweener.kill();
				_fadeOutTweener = null;
				try{
					_preNs.close();
				}
				catch(err :Error){};
			}
			if(_fadeInTweener){
				_fadeInTweener.kill();
				_fadeInTweener = null;
			}
		}
		
		private function __onMusicStaus(e:NetStatusEvent):void
		{
			if(e.info.code == "NetConnection.Connect.Failed" || e.info.code == "NetStream.Play.StreamNotFound")
			{
				if(_currentMusicTry < MusicFailedTryTime)
				{
					_currentMusicTry++;
					_curNs.play(_musicSite + _currentMusic + ".flv");
				}else
				{
					_curNs.removeEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
					try{
						_curNs.close();
					}
					catch(err :Error){};
				}
			}else if (e.info.code == "NetStream.Play.Start")
			{
				_curNs.removeEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
				//_preNs.close();
				if(_fadeOutTweener){
					_musicCanStart = true;
					pauseMusic();
				}else{
					
				}
			}
		}
		
		public function pauseMusic():void
		{
			if(_musicPlaying)
			{
				_curNs.pause();
				_musicPlaying = false;
			}
		}
		
		public function resumeMusic():void
		{
			if(_allowMusic && _currentMusic)
			{
				_curNs.resume();
				_musicPlaying = true;
			}
		}
		
		public function stopMusic():void
		{
			if(_currentMusic)
			{
				_musicPlaying = false;
				try{
					_curNs.close();
				}
				catch(err :Error){};
				_currentMusic = null;
				_currentMusicIndex = -1;
			}
		}
		private function __netStatus(e:NetStatusEvent):void
		{
			if(e.info.code == "NetStream.Play.Stop")
			{
				if(_musicLoop)
				{
					playMusicImp(_currentMusicIndex, _musicLoop);
				}
				else
				{
					_currentMusicIndex++;
					playMusicImp(_currentMusicIndex, _musicLoop);
				}
			}
		}
		public function onMetaData(info:Object):void {}
		
		public function onPlayStatus(info:Object):void {}
		
		public function playExtraMusic(str:String,loops:Boolean = true):void
		{
			prepared();
			_musicPlaying = true;
			_curNs.play(str);
			_curNs.soundTransform = new SoundTransform(0);//new SoundTransform(_musicVolumn / 100);
			
			if(_allowMusic)
			{
				_musicCanStart = false;
				_curNs.addEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
				removeMusicTweener();
				var sndChannel : SoundTransform = new SoundTransform(_musicVolumn / 100);
				_fadeOutTweener = TweenLite.to(sndChannel, 1.5, {volume:0.4, onUpdate:updateFadeOutChannel, 
					onUpdateParams:[_preNs, sndChannel], onComplete : musicFadeOutComplete,
					onCompleteParams:[_preNs]});
			}
			else
			{
				_curNs.removeEventListener(NetStatusEvent.NET_STATUS,__onMusicStaus);
				pauseMusic();
			}
		}
		//===================================播放背景音乐====================================
		private static var _instance:SoundManager;
		public static function get instance():SoundManager
		{
			if(!_instance)_instance=new SoundManager();
			return _instance;
		}
	}
}